// 手写实现Promise源码

// 关于状态，三种
// 1 对象的状态不受外界影响
// 2 一旦状态改变，就不会再变，任何时候都可以得到这个结果
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失败

class MyPromise {
  status = PENDING;
  // 成功之后的值
  value = null;
  // 失败后的原因
  reason = null;
  // 成功状态函数收集器
  successBackCollection = [];
  // 失败状态函数收集器
  failBackCollection = [];
  constructor(excutor) {
    // excutor 实例化Promise的同步回调
    // 错误处理，健壮性
    try {
      excutor(this.resolve, this.reject);
    } catch (e) {
      this.reject(e);
    }
  }
  // 成功状态，存储值，多个成功回调
  resolve = (value) => {
    // 如果状态不是等待 阻止程序向下执行
    if (this.status !== PENDING) return;
    // 状态更改为成功
    this.status = FULFILLED;
    // 保存成功之后的值
    this.value = value;
    // 如果有成功回调，依次执行
    while (this.successBackCollection.length) {
      this.successBackCollection.shift()();
    }
  };
  // 失败状态，存储原因，多个失败回调
  reject = (reason) => {
    if (this.status !== PENDING) return;
    // 将状态更改为失败
    this.status = REJECTED;
    // 保存失败后的原因
    this.reason = reason;
    // 判断失败回调是否存在 如果存在 调用
    while (this.failBackCollection.length) {
      this.failBackCollection.shift()();
    }
  };

  then = (successCallback, failCallback) => {
    // 成功，失败参数可选，兼容promise.then().then().then((value)=>{console.log(value)})传空值的情况
    successCallback = successCallback ? successCallback : (value) => value;
    failCallback = failCallback
      ? failCallback
      : (reason) => {
          throw reason;
        };
    const promise2 = new MyPromise((resolve, reject) => {
      // 统一使用一个setTimeout，虽不是同步了，但实际执行顺序不受影响，减少setTimeout使用，（待认证）
      setTimeout(() => {
        // 状态改变直接执行回调
        if (this.status === FULFILLED) {
          try {
            let x = successCallback(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        } else if (this.status === REJECTED) {
          try {
            let x = failCallback(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        } else {
          // 异步情况，状态未改变，存储回调
          this.successBackCollection.push(() => {
            try {
              let x = successCallback(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
          this.failBackCollection.push(() => {
            try {
              let x = failCallback(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        }
      }, 0);
    });
    return promise2;
  };
  // 获取失败原因，执行失败状态回调函数
  catch(failCallback) {
    this.then(undefined, failCallback);
  }
  // 1 不管promise最后的状态，在执行完then或catch指定的回调函数以后，都会执行finally方法指定的回调函数
  // 2 finally本质上是then方法的特例。
  finally(callBack) {
    return this.then(
      (value) => {
        return MyPromise.resolve(callBack(value)).then((value) => {
          return value;
        });
      },
      (reason) => {
        return MyPromise.resolve(callBack(reason)).then(() => {
          throw reason;
        });
      }
    );
  }
  // 将目标转换成promise，并返回resolve状态
  static resolve(value) {
    if (value instanceof MyPromise) {
      return value;
    } else {
      return new MyPromise((resolve) => {
        resolve(value);
      });
    }
  }
  // 将目标转换成promise，并返回reject状态
  static reject(reason) {
    if (reason instanceof MyPromise) {
      return reason;
    } else {
      return new MyPromise((resolve, reject) => {
        reject(reason);
      });
    }
  }
  // 只要数组promise，如p1,p2,p3的状态都变成fulfilled，p的状态才会变成fulfilled，此时p1、p2、p3的返回值组成一个数组，传递给p的回调函数。
  // 只要数组promise，如p1,p2,p3之中有一个被rejected，p的状态就变成rejected，此时第一个被reject的实例的返回值，会传递给p的回调函数
  static all(array) {
    const length = array.length;
    let result = [];
    let i = 0;
    return new MyPromise((resolve, reject) => {
      function addData(key, value) {
        result[key] = value;

        if (++i >= length) {
          resolve(result);
        }
      }
      for (let i = 0; i < length; i++) {
        if (i >= length) {
          resolve(result);
          return;
        }
        const current = array[i];
        if (current instanceof MyPromise) {
          current.then(
            (value) => {
              addData(i, value);
            },
            (reason) => {
              reject(reason);
            }
          );
        } else {
          addData(i, current);
        }
      }
    });
  }
  // 只要数组promise，如p1,p2,p3之中有一个实例率先改变状态，p的状态就跟着改变。那个率先改变的 Promise 实例的返回值，就传递给p的回调函数
  static race(array) {
    const length = array.length;
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < length; i++) {
        const current = array[i];
        if (current instanceof MyPromise) {
          current.then(
            (value) => {
              resolve(value);
            },
            (reason) => {
              reject(reason);
            }
          );
        } else {
          resolve(current);
        }
      }
    });
  }
}

// 1 判断 x 的值是普通值还是promise对象
// 2 如果是普通值 直接调用resolve
// 3 如果是promise对象 查看promsie对象返回的结果
// 4 再根据promise对象返回的结果 决定调用resolve 还是调用reject
function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(
      new TypeError("Chaining cycle detected for promise #<Promise>")
    );
  }
  if (x instanceof MyPromise) {
    x.then(
      (value) => {
        resolve(value);
      },
      (reason) => {
        reject(reason);
      }
    );
  } else {
    resolve(x);
  }
}

module.exports = MyPromise;
